﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Web;
using System.Runtime.Serialization.Formatters.Binary;
using ICSharpCode.SharpZipLib.BZip2;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.GZip;
using HttpClientLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UpdatorYaml;
using System.Diagnostics;

namespace Updator
{
    public partial class Updator : Form
    {
        
        public Updator()
        {
            InitializeComponent();
        }

        #region 界面事件

        private void Updator_Load(object sender, EventArgs e)
        {
            _httpClientMethod = new HttpClientMethod();
            yaml = new YamlDecode();
            logger = new Logger(Logpath);
            pictureBox1.Image = new Bitmap(Application.StartupPath + @"\1.jpg");
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
        }

        private int timerCount = 0;

        private void timer1_Tick(object sender, EventArgs e)
        {
            timerCount++;
            if (timerCount == 2)
            {
                Main();
                timer1.Enabled = false;
            }
        }

        #endregion

        #region Log
        private Logger logger;
        private string Logpath = Application.StartupPath + @"\Log\log.md";
        #endregion

        #region 获取周刊工具路径
        private string ToolsPath = string.Empty;
        private string AppymlPath = string.Empty;
        private string RootPath = string.Empty;
        private bool isATools = true;
        private bool isAppyml = true;
        private string GetToolsPath()
        {
            string path = Application.StartupPath;
            path = Directory.GetParent(path).FullName;
            string atoolspath = path + @"\atools.exe";
            if (!File.Exists(atoolspath))
            {
                isATools = false;
                Main_lbl_Current.Text = @"炉子坏了，吃不了汤圆了....";
                Main_tslbl_Status.Text = @"工具路径下atools.exe不存在，请联系K.sr解决。";
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"工具路径不存在");
                Application.DoEvents();
                return string.Empty;
            }
            Application.DoEvents();
            logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"获取工具路径成功");
            return atoolspath;
        }

        private string GetAppymlPath()
        {
            string path = Application.StartupPath;
            path = Directory.GetParent(path).FullName;
            path = Directory.GetParent(path).FullName;
            string appymlpath = path + @"\app.yml";
            if (!File.Exists(appymlpath))
            {
                isAppyml = false;
                Main_lbl_Current.Text = @"汤圆吃光了...";
                Main_tslbl_Status.Text = @"app.yml文件不存在，请联系K.sr解决。";
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"app.yml路径不存在");
                Application.DoEvents();
                return string.Empty;
            }
            logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"获取app.yml路径成功");
            Application.DoEvents();
            return appymlpath;
        }

        private string GetRootPath()
        {
            string path = Application.StartupPath;
            path = Directory.GetParent(path).FullName;
            path = Directory.GetParent(path).FullName;
            logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"获取根路径成功");
            return path;
        }

        #endregion

        #region 本地版本验证

        private int VersionCode = 0;
        private string ToolName = string.Empty;
        private bool isVersion = true;
        private bool isToolName = true;
        private YamlDecode yaml;
        private void ReadYML()
        {
            Main_tslbl_Status.Text = @"正在获取本地版本...";
            Application.DoEvents();
            try
            {
                FileStream fs = new FileStream(AppymlPath, FileMode.Open, FileAccess.Read);
                StreamReader sr = new StreamReader(fs);
                string Content = sr.ReadToEnd();
                VersionCode = yaml.GetVersionCode(Content);
                if (VersionCode == -1)
                {
                    isVersion = false;
                }
                ToolName = yaml.GetToolName(Content).Replace("\n", "");
                if (ToolName == string.Empty)
                {
                    isToolName = false;
                }
                sr.Close();
                fs.Close();
                Main_tslbl_Status.Text = @"获取本地版本成功...";
                string showversion = VersionCode.ToString();
                if (showversion.Length == 2 )
                {
                    showversion = "0" + showversion;
                }
                if (showversion.Length == 1)
                {
                    showversion = "00" + showversion;
                }
                Main_lbl_LocalVersion.Text = @"我的碗：" + showversion;

                logger.Log(DateTime.Now.ToString("yy-mm-dd hh:mm:ss ----") + @"读取yml成功，版本号为：" + VersionCode);
                Application.DoEvents();
            }
            catch (Exception ex)
            {
                Main_tslbl_Status.Text = @"读取yml失败，错误代码为：" + ex.Message;
                Main_lbl_Current.Text = @"揭不开锅了...";
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"读取yml失败");
            }
            
        }

        #endregion

        #region 联机版本验证

        private HttpClientMethod _httpClientMethod;
        private int CurrentVersionCode = 0;
        private string GenerateContent()
        {
            return @"versionCode=" + VersionCode + @"&name=" + ToolName;
        }

        private void GetCurrentVersion()
        {
            try
            {
                Main_tslbl_Status.Text = @"正在获取最新版本...";
                Application.DoEvents();
                string recStr = _httpClientMethod.Get(Main_txb_ServerURL.Text, GenerateContent());
                JObject json = JObject.Parse(recStr);
                string returnCode = json["code"].ToString();
                if (int.Parse(returnCode) < 0)
                {
                    CurrentVersionCode = VersionCode;
                    Main_lbl_CurrentVersion.Text = "他的锅：" + CurrentVersionCode;
                    logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"本地版本与联机版本一致或超出，返回code为：" + returnCode);
                    Application.DoEvents();
                }
                else
                {
                    JObject json1 = (JObject)JsonConvert.DeserializeObject(recStr);
                    JObject json2 = (JObject)json1["data"];
                    string detail = json2["detail"].ToString();
                    Main_txb_UpdateLog.Text = "我爱吃汤圆--By熊妹" + Environment.NewLine + detail;
                    Application.DoEvents();
                    string currentversion = json2["versionCode"].ToString();
                    CurrentVersionCode = int.Parse(currentversion);
                    Main_lbl_CurrentVersion.Text = "他的锅：" + currentversion;
                    Application.DoEvents();
                    DownloadFileUrl = json2["url"].ToString();
                    logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"本地版本较低，需更新，返回code为：" + returnCode + "---更新文件下载地址为：" + DownloadFileUrl);
                }
                Main_tslbl_Status.Text = @"最新版本获取成功...";
            }
            catch (Exception e)
            {
                Main_lbl_Current.Text = @"汤圆卖光了...";
                Main_tslbl_Status.Text = "获取联机版本失败！清联系K.sr确认服务器地址！错误代码为：" + e.Message;
                logger.Log(DateTime.Now.ToString("yy-mm-dd hh:mm:ss ----") + @"获取联机版本失败，exception：" + e.Message);
                Application.DoEvents();
            }
          
        }

        private bool VersionCompare()
        {
            if (VersionCode == CurrentVersionCode)
            {
                return true;
            }
            return false;
        }
        

        #endregion

        #region 周刊工具文件下载

        private string DownloadFileUrl = string.Empty;
        private void DownloadFile(string url, string filename, ProgressBar prog, Label label)
        {
            label.Text = "煮呀么煮汤圆"; 
            Main_tslbl_Status.Text = "开始下载更新";
            Application.DoEvents();
            string tmpPath = Path.GetDirectoryName(filename) + @"\temp";
            Directory.CreateDirectory(tmpPath);
            string tmpFile = tmpPath + @"\" + Path.GetFileName(filename) + ".temp";
            if (File.Exists(tmpFile))
            {
                File.Delete(tmpFile);
            }
            try
            {
                FileStream fs = new FileStream(tmpFile,FileMode.Append,FileAccess.Write,FileShare.ReadWrite);
                HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                double filelength = response.ContentLength;
                if (prog != null)
                {
                    prog.Maximum = (int)filelength;
                }
                Stream responseStream = response.GetResponseStream();
                byte[] bArr = new byte[1024];
                int size = responseStream.Read(bArr, 0, (int) bArr.Length);
                double currentlength = 0;
                while (size > 0)
                {
                    currentlength = size + currentlength;
                    Application.DoEvents();
                    fs.Write(bArr,0,size);
                    if (prog != null)
                    {
                        prog.Value = (int) currentlength;
                    }
                    size = responseStream.Read(bArr, 0, (int) bArr.Length);
                    Thread.Sleep(50);
                    if (currentlength / 1024 /1024 <= 10)
                    {
                        label.Text = "已经煮了" + (currentlength / 1024).ToString("F") + @"个汤圆，共有" + (filelength / 1024).ToString("F") + @"个汤圆";
                        Main_tslbl_Status.Text = "当前下载大小" + (currentlength / 1024).ToString("F") + @"KB，文件总大小" + (filelength / 1024).ToString("F") + @"KB";
                    }
                    else
                    {
                        label.Text = "已经煮了" + (currentlength / 1024 / 1024 ).ToString("F") + @"个汤圆，共有" + (filelength / 1024 / 1024).ToString("F") + @"个汤圆";
                        Main_tslbl_Status.Text = "当前下载大小" + (currentlength / 1024 / 1024).ToString("F") + @"MB，文件总大小" + (filelength / 1024 /1024).ToString("F") + @"MB";
                    }
                    Application.DoEvents();
                }
                fs.Close();
                responseStream.Close();
                File.Move(tmpFile,filename);
                File.Delete(tmpFile);
                logger.Log(DateTime.Now.ToString("yy-mm-dd hh:mm:ss ----") + @"更新文件下载成功，总大小：" + size);
            }
            catch (Exception e)
            {
                label.Text = @"汤圆煮糊了！！！";
                Main_tslbl_Status.Text = "下载错误！错误代码为：" + e.Message;
                logger.Log(DateTime.Now.ToString("yy-mm-dd hh:mm:ss ----") + @"下载失败，exception：" + e.Message);
                Application.DoEvents();
            }
        }
        #endregion

        #region 周刊工具解压

        public bool UnZip(string fileToUnZip, string zipedFolder, string password)
        {
            bool result = true;
            FileStream fs = null;
            ZipInputStream zipStream = null;
            ZipEntry ent = null;
            string fileName;

            if (!File.Exists(fileToUnZip))
                return false;

            if (!Directory.Exists(zipedFolder))
                Directory.CreateDirectory(zipedFolder);

            try
            {
                zipStream = new ZipInputStream(File.OpenRead(fileToUnZip));
                if (!string.IsNullOrEmpty(password)) zipStream.Password = password;
                while ((ent = zipStream.GetNextEntry()) != null)
                {
                    if (!string.IsNullOrEmpty(ent.Name))
                    {
                        fileName = Path.Combine(zipedFolder, ent.Name);
                        fileName = fileName.Replace('/', '\\');//change by Mr.HopeGi   

                        int index = ent.Name.LastIndexOf('/');
                        if (index != -1 || fileName.EndsWith("\\"))
                        {
                            string tmpDir = (index != -1 ? fileName.Substring(0, fileName.LastIndexOf('\\')) : fileName) + "\\";
                            if (!Directory.Exists(tmpDir))
                            {
                                Directory.CreateDirectory(tmpDir);
                            }
                            if (tmpDir == fileName)
                            {
                                continue;
                            }
                        }

                        fs = File.Create(fileName);
                        int size = 2048;
                        int count = 0;
                        byte[] data = new byte[size];
                        while (true)
                        {
                            count += 1;
                            if (count == 999)
                            {
                                count = 998;
                            }
                            size = zipStream.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                fs.Write(data, 0, data.Length);
                                if (Main_pgb_progress != null)
                                {
                                    Main_pgb_progress.Value = count;
                                }
                            }
                            else
                            {
                                if (Main_pgb_progress != null)
                                {
                                    Main_pgb_progress.Value = 1000;
                                }
                                break;
                            }
                            Application.DoEvents();
                        }
                    }
                }
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"解压成功");
            }
            catch(Exception ex)
            {
                Main_lbl_Current.Text = @"吃汤圆时，一不小心碗掉了...请联系熊妹，帮你再来一碗";
                Main_tslbl_Status.Text = @"解压失败，错误代码为:" + ex.Message;
                logger.Log(DateTime.Now.ToString("yy-mm-dd hh:mm:ss ----") + @"解压失败，exception:" + ex.Message);
                result = false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                }
                if (zipStream != null)
                {
                    zipStream.Close();
                    zipStream.Dispose();
                }
                if (ent != null)
                {
                    ent = null;
                }
                GC.Collect();
                GC.Collect(1);
            }
            return result;
        }

        private void Unzip(string filepath)
        {
            Main_tslbl_Status.Text = "文件下载成功，开始解压";
            Main_lbl_Current.Text = "汤圆煮好啦，正在吃汤圆";
            Application.DoEvents();
            if (UnZip(filepath, RootPath, null))
            {
                Main_lbl_Current.Text = "汤圆吃完惹";
                Main_tslbl_Status.Text = "文件解压完成";
                Application.DoEvents();
            }
            Thread.Sleep(100);
        }

        #endregion

        #region 启动周刊工具
        private bool StartAtools()
        {
            try
            {
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = ToolsPath;
                psi.UseShellExecute = true;
                psi.CreateNoWindow = true;
                psi.WorkingDirectory = Directory.GetParent(ToolsPath).FullName;
                Process.Start(psi);
                //Process.Start(ToolsPath);
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"启动atools.exe成功， atools.exe路径:" + ToolsPath);
                return true;
            }
            catch (Exception ex)
            {
                Main_lbl_Current.Text = "汤圆爆炸了...请联系K.sr或者熊妹修复";
                Main_tslbl_Status.Text = "启动atools.exe失败，错误代码为：" + ex.Message;
                logger.Log(DateTime.Now.ToString("yy-MM-dd hh:mm:ss ----") + @"启动atools.exe失败，错误代码为：" + ex.Message);
                Application.DoEvents();
                return false;
            }
            
        }
        #endregion

        #region 主要流程

        private void Main()
        {
            //获取atools.exe文件路径
            ToolsPath = GetToolsPath();
            //如果atools.exe不存在 退出更新
            if (!isATools)
            {
                return;
            }
            //获取app.yml文件路径
            AppymlPath = GetAppymlPath();
            //如果app.yml不存在 退出更新
            if (!isAppyml)
            {
                return;
            }
            //获取根目录路径
            RootPath = GetRootPath();
            //获取本地app.yml文件中的name和VersionCode
            ReadYML();
            //获取联机中VersionCode
            if (isToolName && isVersion)
            {
                GetCurrentVersion();
                //对比版本号
                if (!VersionCompare())
                {
                    string toolspath = Directory.GetParent(RootPath).FullName;
                    string toolfilename = RootPath.Replace(toolspath, "").Replace(@"\", "");
                    DownloadFile(DownloadFileUrl, Application.StartupPath + @"\" + toolfilename + @".zip", Main_pgb_progress, Main_lbl_Current);
                    Unzip(Application.StartupPath + @"\" + toolfilename + @".zip");
                    try
                    {
                        File.Delete(Application.StartupPath + @"\" + toolfilename + @".zip");
                        Directory.Delete(Application.StartupPath + @"\temp");
                    }
                    catch (Exception)
                    {

                    }
                }
                Main_lbl_Current.Text = @"汤圆都被基佬蝶偷吃完了！";
                Main_tslbl_Status.Text = @"即将启动atools.exe";
                Application.DoEvents();
            }
            else
            {
                Main_lbl_CurrentVersion.Text = "他没有锅！！！";
                Main_tslbl_Status.Text = @"本地版本号不存在";
            }
            Main_txb_UpdateLog.Visible = false;
            pictureBox1.Visible = true;
            Application.DoEvents();
            Thread.Sleep(5000);
            if (StartAtools())
            {
                Thread.Sleep(3000);
                Main_lbl_Current.Text = @"抓住基佬蝶了！";
                Main_tslbl_Status.Text = @"启动成功，即将退出Updator.exe";
                Application.DoEvents();
                Application.Exit();
            }
            else
            {
                Thread.Sleep(3000);
            }

            return;

        }

        private void Main_btn_Run_Click(object sender, EventArgs e)
        {
            Main();
        }

        #endregion
    }
}
